// -*- swift -*-
// RUN: %target-run-simple-swiftgyb
// REQUIRES: executable_test

%{
from gyb_stdlib_support import (
    TRAVERSALS,
    sliceTypeName,
    defaultIndicesForTraversal
)
}%

import StdlibUnittest
import StdlibCollectionUnittest


/// Reference-type collection for testing the `base` property.
class ReferenceCollection : RandomAccessCollection {
  typealias Index = Int

  var startIndex: Int {
    return 0
  }

  var endIndex: Int {
    return 1
  }

  subscript(index: Int) -> String {
    return ""
  }

  func index(after i: Int) -> Int {
    return 1
  }

  func index(before i: Int) -> Int {
    return 0
  }
}

var SliceTests = TestSuite("Collection")

//===----------------------------------------------------------------------===//
// Slice<Base>
//===----------------------------------------------------------------------===//

% for Traversal in TRAVERSALS:
%   for Mutable in [ False, True ]:
%     for RangeReplaceable in [ False, True ]:
%       Slice = sliceTypeName(traversal=Traversal, mutable=Mutable, rangeReplaceable=RangeReplaceable)
%       Collection = 'Minimal' + Slice.replace('Slice', 'Collection')

SliceTests.test("${Slice}/AssociatedTypes") {
 do {
    typealias Collection = ${Collection}<OpaqueValue<Int>>
    typealias CollectionSlice = ${Slice}<Collection>
    expectSliceType(CollectionSlice.self)
    expectCollectionAssociatedTypes(
      collectionType: CollectionSlice.self,
      iteratorType: IndexingIterator<CollectionSlice>.self,
      subSequenceType: CollectionSlice.self,
      indexType: MinimalIndex.self,
      indexDistanceType: Int.self,
      indicesType: ${defaultIndicesForTraversal(Traversal)}<CollectionSlice>.self)
  }

  func checkStaticTypealiases1<Base : Collection>(_: Base) {
    expectEqualType(Base.Index.self, Slice<Base>.Index.self)
  }

  func checkStaticTypealiases2<
    Base : MutableCollection
  >(_: Base) {
    expectEqualType(Base.Index.self, MutableSlice<Base>.Index.self)
  }
}

SliceTests.test("${Slice}/init(base:bounds:)") {
  for test in subscriptRangeTests {
    let base = ${Collection}(elements: test.collection)
    var slice = ${Slice}(base: base, bounds: test.bounds(in: base))
    expectType(${Slice}<${Collection}<OpaqueValue<Int>>>.self, &slice)

    checkCollection(
      test.expected,
      slice,
      stackTrace: SourceLocStack().with(test.loc))
      { $0.value == $1.value }
  }
}

% if RangeReplaceable == False and Mutable == False:
SliceTests.test("${Slice}/baseProperty") {
  let referenceCollection = ReferenceCollection()
  let testSlice = ${Slice}(base: referenceCollection, bounds: 0..<1)
  expectTrue(testSlice.base === referenceCollection)
}
% end

SliceTests.test("${Slice}.{startIndex,endIndex}") {
  for test in subscriptRangeTests {
    let c = ${Collection}(elements: test.collection)
    let bounds = test.bounds(in: c)
    var slice = ${Slice}(base: c, bounds: bounds)
    expectType(${Slice}<${Collection}<OpaqueValue<Int>>>.self, &slice)

    expectEqual(bounds.lowerBound, slice.startIndex)
    expectEqual(bounds.upperBound, slice.endIndex)
  }
}

%     end
%   end
% end

//===----------------------------------------------------------------------===//
// MutableSlice<Base>
//===----------------------------------------------------------------------===//

/*
FIXME: uncomment this test when the following bug is fixed:

<rdar://problem/21935030> Recast Slice and MutableSlice in terms of Collection
and MutableCollection

extension MutableSlice {
  func _checkBaseSubSequenceElementIsElement() {
      Element.self,
      Iterator.Element.self)
    expectEqualType(
      Element.self,
      Iterator.Element.self,
      Base.Iterator.Element.self)
    expectEqualType(
      Element.self,
      Iterator.Element.self,
      Base.SubSequence.Iterator.Element.self)
  }
}
*/

runAllTests()
